/**
 * 表格插件：将整理JQuery DataTable、JQuery TreeTable到此
 */
var ComTable = new CommonTable();
/**
 * 为了兼容其他使用了此方法的脚本此方法暂时不除去,为了防止和其他脚本中全局同名方法冲突被覆盖,请尽量不使用此方法,建议使用ComTable.initDTable()
 * @param url
 * 初始化表格
 * @param param
 * 远程访问地址参数,格式为：{id:001}
 * @param columns
 * 列明,JSON数组:{"data":"userid"}, {"data":"username" }, {"data":"mobiletel"}, {"data": "email"},...]
 * @param colDefs
 * 列自定义,[{"render" : function(data, type, row) {//data为本单元格值，type为filter、display、type、sort，row为整行数据 
 * 			return htmlcode;	
 * },targets : 2// 指定需要自定义的列
 * }]
 * @returns
 */
/*function intTable(url,param,columns,colDefs) {
	ComTable.initDTable('#sample-table', url, param, columns, colDefs);
}*/
function CommonTable(){
	var that = this;
	
	/**
	 * 按照JQuery.dataTable API要求的格式传入相关参数初始化表格
	 * @param obj
	 * 表格对象,形如'#tableId','.tableClazz'
	 * @param url
	 * Ajax远程数据服务地址
	 * @param param
	 * Ajax请求远程服务地址需要的JSON对象参数，可为空{}
	 * @param columns
	 * 表格字段在数据中唆对应的ID，形如：[{"data":"userid"}, {"data":"username"}, {"data":"column3"},{...}]
	 * @param colDefs
	 * 表格列自定义,形如：
	 * [{"render" : // 处理函数
	 *    function(data, type, row) {//data为本单元格值,type为filter、display、type、sort,row为整行数据 
	 *  	 return data == 'y' ? '<span class="label label-sm label-warning">禁用</span>' : ' <span class="label label-sm label-success">启用</span>'; 
	 * 	  }, 
	 *    "targets" : 4// 代表第几列,序号从0开始计算 
	 * },{...//其他列}]
	 */
	that.initDTable = function(obj,url,param,columns,colDefs){
		var options = $.extend({}, {
			ajax : {
				url : url,
				data : param
			},
			columns : columns,
			columnDefs : colDefs
		});
//		$(obj).dataTable(options);
		ComTable.DTable(obj,options);
	}
	
	/**
	 * 初始化表格JQuery.datatable
	 * @param obj
	 * 表格对象ID,请尽量使用#tableId,少使用类.mytable
	 * @param options
	 * 配置项
	 */
	that.DTable = function(obj, options) {
		if (!$(obj)) {
			return;
		}
		// 先将表格字段设置转成JsonArr
		if (options.columns && ComUtil.isJson(options.columns)) {
			options.columns = ComTable.jsonArray(options.columns);
		}
		options = $.extend({},{
			debug :	false,		// 是否调试
			processing : false,	// 是否表示 "processing" 加载中的信息，这个信息可以修改
			serverSide : true,	// 服务器端处理方式
			ajax : {// 服务器端Ajax
				url: '',
				type: 'POST',
				data: {},
				dataSrc: function(data){//用于处理服务器端返回的数据
					// nothing todo here...
				}
			},
			/**
			 * columns
			 * 列定义: [{data:'xx',className:'dt-body-right',width:40,render:function(cell, type, row, meta){}},...]
			 * data:"idname" 				// 可以是属性名，或嵌套属性（item.id）,数组ArrOne[,] 用中括号中的字符连接数组后返回。
			 * title: "My column title",	// 列头文字，如果没有指定thead，则会生成。如何指定了thead，则会覆盖当前列头文
			 * className:'dt-body-right'	// 这里的class会应用到td上面
			 * width:40						// 列宽
			 * render:function(cell, type, row, meta){// 单元格处理函数
			 * 		cell：当前cell的值，这个值和type有关；
			 * 		type：值由filter,display,type,sort组成；
			 * 		row:当前行数据；
			 * 		meta:未探索?
			 * }
			 * cellType : "td",					// 单元格类型："th","td"
			 * defaultContent: "<i>Not set</i>",// defaultContent:默认值，属性值为null或undefined就会用这个值
			 * orderable : true,		    // 是否可排序 默认值：true
			 * orderData : [0, 1],			// 指定当前列排序操作的时候，用哪一列（几列）的数据进行真正的排序（通常是隐藏的）
			 * orderDataType : "dom-text",	// 这个属性 和type属性相似，指定排序时候这一列该怎么转换数据,需要用到其他的插件[具体参考：https://datatables.net/plug-ins/sorting/]
			 * visible: false,				// 是否显示当前列 默认值：true
			 * searchable: false,			// 是否允许搜索此列 默认值：true
			 * createdCell:function(cell, cellData, rowData, row, col){// 单元格创建完后的回调，可以作为render的补充
			 * 	// cell:TD的dom
				// cellData:原始的单元格数据，如何render中进行了格式化，用$(cell).html()来取格式化后的数据
                // rowData:行数据
                // row:行号
                // col:列号
			 * }
			 */
			columns: [],			// 列定义
			columnDefs: [] ,		// 和上面的columns类似，columns可以定义的属性,都可以在这里定义,另外增加targets属性用于指定列范围（可以多列）, 优先级：上面的columns高于columnDefs
//			rowId:'',				// 指定用于行ID的属性名,请用到时自定义
			autoWidth: true,		// 自动列宽
			destroy: true,			// 每次创建是否销毁以前的DataTable,默认false
			scrollCollapse: false,
			ordering: true,			// 是否允许排序
			/**
			 * 翻页按钮样式:
			 * numbers:数字;
			 * simple:前一页，后一页;
			 * simple_numbers:前一页，后一页，数字;
			 * full:第一页，前一页，后一页，最后页;
			 * full_numbers:第一页，前一页，后一页，最后页，数字;
			 * first_last_numbers:第一页，最后页，数字
			 */
			pagingType : 'full_numbers',
			language : {
				sProcessing : '处理中...',
				lengthMenu : '每页 _MENU_ 条',
				zeroRecords : "没有匹配结果",
				info : '第 _START_ 至 _END_ 条，共 _TOTAL_ 条',
				infoEmpty : '显示第 0 至 0 项结果，共 0 项',
				infoFiltered : '(由 _MAX_ 项结果过滤)',
				infoPostFix : '',
				search : '搜索:',
				url : '',
				emptyTable : '表中数据为空',
				loadingRecords : '载入中...',
				thousands : ',',
				paginate : {
					first : '首页',
					previous : '上页',
					next : '下页',
					last : '末页'
				},
				aria : {
					sSortAscending : ': 以升序排列此列',
					sSortDescending : ': 以降序排列此列'
				}
			},
			/**
			 * 行样式应用,指定多个的话,第一行tr的class为strip1，第二行为strip2，第三行为strip3.
			 * 第四行以后又开始从strip1循环...如果想指定成斑马条状，这里的class必须指定为2个。
			 */
//			stripeClasses: ['strip1', 'strip2', 'strip3'],
			searching : false,						// 是否允许检索
			lengthChange : true,					// 条数选择功能 默认true
			lengthMenu: [ 20, 30, 50, 100, 200 ],	// 条数选择下拉框内容
			pageLength : 20,	// 每页的初期条数 用户可以操作lengthMenu上的值覆盖
            paging: true,		// 是否允许翻页，设成false，翻页按钮不显示
//          scrollX: true,		// 水平滚动条
//          scrollY: true, 		// 垂直滚动条
            /**
             * <div class="top">{information}</div>{processing}{table}<div class="bottom">{filter}{length}{pagination}</div><div class="clear"></div>
             */
            dom : '<"top">rt<"bottom"iflp><"clear">',	// 控制表格各种信息的表示位置（比较复杂）,具体参考[https://datatables.net/reference/option/dom]
            // TODO 绘制事件函数
            /**
             * createdRow
             * 每一行创建完调用的函数
             * row : tr dom
             * data: row data
             * dataIndex:row data's index
             */
            createdRow: function(row, data, dataIndex){ // 每一行创建完调用的函数
            	// nothing todo here...
            },
            rowCallback: function(row, data, dataIndex){// 每一行被创建，但还没有被加载到document中，这个函数优先于createdRow
            	// nothing todo here...
            },
            /**
             * thead:dom 
             * data:原始的datatable数据
             * display：当前显示排序好的
             * datatable数据（有可能经过排序）
             * start end ：当前dispaly数据的开始结束序号
             */
            headerCallback: function(thead, data, start, end, display){//thead被描画后调用
            	// nothing todo here...
            },
            /**
             * tfoot:do
             * data:原始的datatable数据
             * display：当前显示排序好的
             * datatable数据（有可能经过排序）
             */
            footerCallback: function(tfoot, data, start, end, display){// tfoot被描画后调用，通常可用于计算合计值
            	// nothing todo here...
            },
            /**
             * 初始化，描画都已经完成，常用于ajax
             */
            initComplete: function(settings, json){// 初始化，描画都已经完成，常用于ajax
            	try {
            		$('div.loading').remove();
				} catch (e) {}
				// nothing todo here...
            },
            /**
             * 每次DataTable描画后都要调用，调用这个函数时，table可能没有描画完成，所以不要在里面操作table的dom，要操作dom应放在initComplete
             */
            drawCallback: function(settings){// 初始化，描画都已经完成，常用于ajax
                // Output the data for the visible rows to the browser's console
            	/*var api = this.api();
                console.log( api.rows( {page:'current'} ).data() );*/
            	// nothing todo here...
            },
            /**
             * 这个函数可以改写数字的格式化方式
             */
            formatNumber: function(toFormat){// 默认DataTable用 language.thousands来解析数字，“，”
            	// nothing todo here...
            	return toFormat.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "'");
            },
            /**
             * 【双击事件由于用的少暂时未封装】
			 * 行点击事件,优先级低于单元格点击事件
			 * @param result
			 * {
			 *		index: index, 		// 单元格索引
			 *		value: value, 		// 单元格值
			 *		row: row, 			// 行数据JSON
			 *		table: table		// datatable对象
			 *	}
			 ***/
            cfgRowCilck: null,
            /**
             * 【双击事件由于用的少暂时未封装】
			 * 单元格点击事件会覆盖单元格行单击事件,如果想同时实现行事件和单元格事件,请使用单元格事件代替行事件,
			 * 在单元格事件中case field ,采用分情况处理
			 * @param result
			 * {
			 *		index: index, 		// 单元格索引 
			 *		value: value, 		// 单元格值
			 *		row: row, 			// 行数据JSON
			 *		table: table		// datatable对象
			 *	}
			 ***/
            cfgCellCilck: null,
            /**
             * 除去哪些列可以不触发单元格点击事件
             */
            cfgCilckIgore: [],
            /**
             * 默认的选中样式CLAZZ
             */
            cfgClickSelected: 'selected',
            /**
             * 是否显示checkbox</br>
             * @see 如何取到已选的行数据
             * Step1:
             * var table = ComTable.DTable('#tableId',options);
             * 或者
             * var table = $('#tableId').DataTable();
             * Step2:
             * var selectedRows = table.rows('.selected').data();
             * 或者使用
             * ComTable.getSelectedRows(table);
             * 获取
             */
            cfgCheck: false,
            /**
             * checkbox
             * 单选:false
			 * 多选:true
             */
            cfgCheckMuti: true,
            /**
             * options.columns中是否已预留checkebox列
             */
            cfgCheckCol: false,
            /**
             * 选中行的样式
             */
            cfgRowCheckClass: 'selected',
		}, options);
		// TODO 设置ajax参数,此句暂时不是多余的,请勿删除
		options.ajax.type = 'POST';
		// TODO 添加CHECKBOX到第一列
		if (options.cfgCheck) {
			var checkBox = '<label><input type="checkbox" class="ace" param /><span class="lbl"></span></label>',
				checkBoxCol = [{
				data: '',
				title: checkBox.replace(/param/g, options.cfgCheckMuti ? '' : 'disabled'),
				width: '15px',
				className: 'center',
				sortable: false,
				searchable: false,
				render: function(cell, type, row, meta){
					return checkBox;
				}
			}];
			if (options.cfgCheckCol) {// 已在columns预留checkboc列
				options.columns[0] = checkBoxCol[0];
			} else {// 没有在columns预留checkboc列
				checkBoxCol.push.apply(checkBoxCol, options.columns);
				options.columns = checkBoxCol;
			}
			
			// TODO 第一列不能排序
			options.columnDefs.push.apply(options.columnDefs,[{
				sortable: false,
				targets : 0
			}]);
			// TODO 取消点击事件列
			options.cfgCilckIgore.push.apply(options.cfgCilckIgore,[0]);
		}
		// TODO 调试专用
		if (options.debug) {
			console.log(options);
			return;
		}
		delete options["debug"];
		$(obj).dataTable(options);
		
		// TODO 设置表格错误拦截方法
		$.fn.dataTable.ext.errMode = 'none';
		$(obj).on('error.dt', function ( e, settings, techNote, message ) {
			// TODO 这里可以接管错误处理，也可以不做任何处理
			if (typeof console !== undefined && typeof console.log === "function") {
				console.log('An error has been reported by DataTables: ', message);
			}
	    }).DataTable();
		
		// TODO 方法1：此方法会同时设置时方法可能会被覆盖(不采纳)
		// TODO 委托行点击事件
		/*if (options.cfgRowCilck && typeof options.cfgRowCilck === "function") {
			$(obj + " tbody").off('click').on('click', 'tr', function (e) {
				var table = $(obj).DataTable(), row = table.row(this), index = row.index(), data = row.data();
				options.cfgRowCilck({
					index: index,
					row: data, 
					table: table
				});
		    });
		}*/
		
		// TODO 委托单元格点击事件,如果同时委托行、单元格事件则上面的行事件将失效只有单元格事件生效
		/*if (options.cfgCellCilck && typeof options.cfgCellCilck === "function") {
			$(obj + " tbody").off('click').on('click', 'td', function (e) {
			    var table = $(obj).DataTable(), cell = table.cell(this), index = cell.index();
				if (options.cfgCilckIgore &&　ComUtil.isArray(options.cfgCilckIgore) 
						&& ComTable.isInArray(index.column, options.cfgCilckIgore)) {
					return;
				}
				var value = cell.data(), row = table.row(index.row).data();
				options.cfgCellCilck({
					index: index,
					value: value, 
					row: row, 
					table: table
				});
		    });
		}*/
		
		// TODO 方法2：行和单元格事件统一进行管理,委托表格点击事件
		$(obj + " tbody").off('click').on('click', 'td', function (e) {
			// 添加选中样式
			var td = this;
			ComTable.selectTr(td, options);
			checkBoxEvent(td, options);
			
			var table = $(obj).DataTable(), cell = table.cell(td);
			// 取消了点击事件的单元格
			if (options.cfgCilckIgore &&　ComUtil.isArray(options.cfgCilckIgore) 
					&& ComTable.isInArray(cell.index().column, options.cfgCilckIgore)) {
				return;
			}
			var result = (function(cell){
				var index = cell.index(), value = cell.data(), row = table.row(index.row).data();
				return {
					index: index,
					value: value, 
					row: row, 
					table: table
				};
			})(cell);
			
			if (options.cfgCellCilck && typeof options.cfgCellCilck === "function") {
				options.cfgCellCilck(result);
			} else {
				if (options.cfgRowCilck && typeof options.cfgRowCilck === "function") {
					options.cfgRowCilck(result);
				}
			}
	    });
		// checkbox事件
		if (options.cfgCheck) {
			// thead的checkbox
			$(obj + ' th input:checkbox:not(:disabled)').on('click' , function(){
				var input = this;
				$(this).closest('table').find('tr td:first-child input:checkbox').each(function(){
					this.checked = input.checked;
					// 添加选中样式
					$(this).closest('tr').toggleClass(options.cfgRowCheckClass);
				});
			});
			// tbody的checkbox
			$(obj + ' tbody td input:checkbox').on('click' , function(){
				checkBoxEvent(this, options);
			});
			var a = setTimeout(() => {
				$(obj + ' thead th input:checkbox').parents('th').removeClass('sorting_disabled').removeClass('sorting_asc').removeClass('sorting_desc');
				clearTimeout(a);
			}, 1000);
		}
		function checkBoxEvent(that, options){
			var rowChecked = options.cfgRowCheckClass;
			if (!options.cfgCheckMuti) {
				$(that).closest('table tbody').find('tr.selected td:first-child input:checkbox').each(function(){
					this.checked = false;
				});
				$(that).closest('table').find('tr.selected').toggleClass('selected');
			}
			$(that).closest('tr').toggleClass(rowChecked);
			$(that).parents('tr').find('td:first-child input:checkbox').each(function(i,o){
				this.checked = $(that).closest('tr').hasClass(rowChecked);
			});
		}
		var timer = setTimeout(() => {
			$(obj).css({
				width: '100%'
			});
			clearTimeout(timer);
		}, 100);
		return $(obj).DataTable();
	}
	
	/**
	 * 添加选中样式
	 */
	that.selectTr = function(tdObj, options){
		options = $.extend({
			cfgClickSelected: 'selected'
		}, options)
		if (options.cfgClickSelected) {
			$(tdObj).parents('tr').siblings('tr').find('td.'+options.cfgClickSelected).removeClass(options.cfgClickSelected);
			$(tdObj).addClass(options.cfgClickSelected).siblings('td').addClass(options.cfgClickSelected);
		}
	}
	
	/**
	 * 判断元素是否在数组中
	 */
	that.isInArray = function(val,arr){
		var isIn = false;
		$.each(arr, function(i, v) {
			if (arr[i] ===  val) {
				isIn = true;
				return false;
			}
		});
		return isIn;
	}
	
	 /** 
     * title: json拆分为json数组(应用于datatable,treetable option表格字段设置)
     * length:数组最大长度，默认取data长度
     * {"data":["id1","id2"],"title":["a1","a2"]}==>[{"data":"id1","title":"a1"},{"data":"id2","title":"a2"}] 
     **/
    that.jsonArray = function(json, length) {
        length = length || json.data.length;
        var nameArr = [],
            data = {},
            jsonArr = [],
            flag = 0;
        for (var i in json) {
            nameArr.push(i);
            if (i == 'title') {
                flag = 1
            }
        };
        for (var i = 0; i < length; i++) {
            data = {};
            for (var j = 0; j < nameArr.length; j++) {
                if (json[nameArr[j]] && json[nameArr[j]][i] || json[nameArr[j]] && json[nameArr[j]][i] == false) {
                    if (!flag) {
                        data.title = 'id' + i
                    };
                    data[nameArr[j]] = json[nameArr[j]][i];
                }
            };
            if (!ComUtil.isEmpty(data)) {
                jsonArr.push(data);
            }
        };
        return jsonArr;
    };
    
    /**
     * 初始化TreeTable
     */
    that.TTable = function(obj, options){
    	var table = $(obj), canlong = typeof console !== undefined && typeof console.log === "function";
    	if (!table) {
    		if (canlong) {
    			console.log('there the obj is null');
    		}
    		return;
    	}
    	if (!options.cfgcols 
    			|| (options.cfgcols && (!options.cfgcols.cid || !options.cfgcols.cname))) {
    		if (canlong) {
    			console.log('there the options.cfgcols is null or not right');
    		}
    		return;
    	}
    	/*************************配置项:开始***********************/
    	// TODO 其他配置项请参见jquery-treetable.js
    	options = $.extend({},{
    		debug: false,				// 是否调试
    		cfgUrlOrData: '',			// 默认的请求数据的URI
			cfgType: 'POST',			// 默认的请求方式POST
			cfgParams: {},				// 默认的请求数据携带的参数
			/**cfgcols: {
				cid:["userid","username","mobiletel","islock"],
				cname:["账号","姓名","电话","状态"],
				width:['15','15',,'10','60'],
				align:['center','center']
			}**/
			cfgcols: null,
			cfgId: 'id',				// 默认的ID
			cfgPid: 'pId',				// 默认的父ID
			/**
			 * @param result
			 * result {
			 * 	cid:...,			// 单元格列名ID
			 *	cx:...,				// 单元格所在行号
			 *	cy:...,				// 单元格所在列号
			 *  cdata:... 			// 行数据
			 *	html:..., 			// 默认就是单元格内容,可更改的
			 *	style:...			// 行样式,可更改的
			 *}
			 * 	
			 * @return 
			 * 返回自行设置的html内容
			 */
			cfgDraw: null,				// 单元格绘制事件,此为默认事件,参数：result
			/**
			 * 【双击事件由于用的少暂时未封装】
			 * 单元格行点击事件,优先级低于单元格点击事件
			 * @param result
			 * {
			 *  field: field,			// 点击的单元格字段ID
			 * 	node: node,				// 树节点信息
			 * 	record: record			// 行数据JSON
			 * }
			 ***/
			cfgRowClick: null,			// 表格行点击事件,参数：result
			/**
			 * 【双击事件由于用的少暂时未封装】
			 * 单元格点击事件会覆盖单元格行事件,如果想同时实现行事件和单元格事件,请使用单元格事件代替行事件,
			 * 在单元格事件中case field ,采用分情况处理
			 * @param result
			 * {
			 * 	field: field,			// 单元格字段ID
			 * 	record: record			// 行数据JSON
			 * 	node: node,				// 树节点信息
			 * }
			 ***/
			cfgCellClick: null,			// 表格单元格点击事件,参数：result
			/**
			 * 树节点展示事件</br>
			 * 函数this指向node,此时取行数据信息为：record = this.row.data("data");
			 */
			onNodeExpand: null, // 树节点展开事件	
			/**
			 * 对表格数据的必要要求：数据请一律事先按照树形结构排好序,排序方式有两种：
			 * (1)后台数据的处理时已对数据转换成[...,children:[{...}]]这样的数据格式;
			 * (2)后台数据的处理时数据数据中无children属性,但是数据已按照树形结构目录排序
			 */
			cfgChilren: true,			// 表格数据JSON中是否已配置chilren
			/**
             * 除去哪些列可以不触发单元格点击事件[0,1,2]
             */
			cfgCilckIgore:[0],			// The number of the column in the table that should be displayed as a tree will not exe click function
			/**
             * 默认的选中样式CLAZZ
             */
            cfgClickSelected: 'selected',
			expandable: true,			// 是否可展,默认false
			expandAll: true,			// 是否自动展开所有
			/**
			 * 指定作为树展示的列,一般默认为第一列,序号为0,此列默认不触发行事件、单元格事件
			 */
			column: 0					// The number of the column in the table that should be displayed as a tree
    	},options);
    	
    	// TODO 调试专用
		if (options.debug) {
			console.log(options);
			return;
		}
    	
    	/*************************配置项:结束***********************/
    	/**
    	 * 绘制表格
    	 */
    	(function fnDrawTable() {
    		var tData;
    		/**
    		 * 表格数据处理
    		 */
    		(function fnTData(){
        		var isUrl = options.cfgUrlOrData && typeof options.cfgUrlOrData === "string";
            	if (isUrl) {
            		ComUtil.AjaxData(obj, options.cfgUrlOrData, function(obj, data) {
            			tData = data.data;
            		}, options.cfgParams,{
            			cfgLoading: false,
            			type: options.cfgType
            		});
            	} else {
            		tData = options.cfgUrlOrData;
            	}
        	})();
    		/**
    		 * 表格数据描绘前先清空以前的数据
    		 */
    		table.treetable('destroy');
        	table.html('');
        	var tbody = fnDrwThead(options.cfgcols.cname);
        	fnDrawTrs(tData,0);
        	
        	/**
        	 * 绘制表头
        	 * 
        	 */
        	function fnDrwThead(cname){
        		var thead = '<thead><tr>',len = cname.length;
            	for (var i = 0; i < len; i++) {
            		thead += '<th' + _setTdStyle(i) + '>' + cname[i] + '</th>';
        		}
            	thead += '</tr></thead>';
            	table.append(thead);
            	table.append('<tbody></tbody>');
            	return table.find("tbody");
        	}
        	
        	/**
        	 * 表格行绘制函数
        	 * @param tData
        	 * 表格行绘制函数
        	 * @param tData
        	 */
        	function fnDrawTrs(rows, x) {
        		if (rows) {
        			// (1)JSON中有children属性,会根据children来设置子级行
        			// (2)JSON中无children属性,目前请使用这种方式
        			for (var i = 0,l = rows.length; i < l; i++) {
        				fnDrawTds(rows[i], x++);
            			if (options.cfgChilren && rows[i].children && ComUtil.isArray(rows[i].children) && rows[i].children.length > 0) {
            				fnDrawTrs(rows[i].children, x);
            			}
        			}
            	} else {
            		if (x === 0) {
            			tbody.append('<tr><td class="center" colspan="' + options.cfgcols.cname.length + '">没有您想要的数据</td></tr>');
            		}
            	}
    		}
        	/**
    		 * @param row
    		 * 表格行数据JSON
    		 * @param cx
    		 * 表格行号
    		 */
    		function fnDrawTds(row, cx){
    			var style = '', td = '', tr = '', cid = options.cfgcols.cid, len = cid.length;
    			for (var c = 0; c < len; c++) {
    				var cellid = cid[c], cvalue = ComUtil.isEmpty(row[cellid]) ? '' : row[cellid],
    				cell = {
    					cid: cellid,			// 单元格列名ID
    					cx: cx,					// 单元格所在行号
    					cy: c,					// 单元格所在列号
    					cdata: row,				// 行数据JSON
    					html: cvalue,			// 默认就是单元格内容
    					style: ''				// 行样式,可更改的
    				};
    				if (options.cfgDraw && typeof options.cfgDraw === 'function') {
    					$.extend({}, cell, options.cfgDraw(cell));
    				}
    				style += cell.style;
    				td += '<td data-field="' + cellid + '" ' + _setTdStyle(c, 'class') + '>' + cell.html + '</td>';
    			}
    			tr = '<tr data-tt-id="'+row[options.cfgId]+'" data-tt-parent-id="'+row[options.cfgPid]+'" style =' + style + '>'+td+'</tr>';
    			tbody.append(tr);
    			// TODO 为行添加数据
    			$('tr[data-tt-id="'+row[options.cfgId]+'"]').data("data", row);
    		}
    		/**
        	 * 取得列文字对齐方式或者样式
        	 * @param col
        	 * @param type
        	 * 	class、width
        	 */
        	function _setTdStyle(col, type) {
        		var cwidth = options.cfgcols.width, calign = options.cfgcols.align,cvalign = options.cfgcols.valign;
        		var style = ' style="vertical-align:center;" ';
        		if (!type) {
        			style += _setTdStyle(col, 'class');
        			style += _setTdStyle(col, 'width');
        			return style;
        		}
        		switch (type) {
    				case 'class':
    					if (calign && calign.length > col && calign[col]) {
    						style += ' ' + type + '="' + calign[col] + '" ';
    		    		}
    					break;
    				case 'width':
    					if (cwidth && cwidth.length > col && cwidth[col]) {
    						style += ' ' + type + '="' + cwidth[col] + '%" ';
    		    		}
    					break;
    				default:
    					break;
    			}
        		return style;
        	}
    	})();
		/**
		 * 将表格穿上TreeTable的外衣
		 */
		table.treetable(options);
		if (options.expandAll) {
			table.treetable('expandAll');
		}
		
		// 方法1：此方法会同时设置时方法可能会被覆盖(不采纳)
    	// TODO 绑定行选择事件
		/*if (options.cfgRowClick && typeof options.cfgRowClick === "function") {
			$(obj + ' tbody').off('click').on('click', 'tr', function (e) {
				var tid = $(this).attr("data-tt-id"), node = table.treetable('node',tid), record = node.row.data("data");
				options.cfgRowClick({
					record: record,
					node: node
				});
		    });
		}*/
		
		// TODO 绑定行选择事件
		/*if (options.cfgCellClick && typeof options.cfgCellClick === "function") {
			$(obj + ' tbody').off('click').on('click', 'td',  function (e) {
				var index = $(this).index();
				if (index === options.column) {
					return;
				}
				if (options.cfgCilckIgore &&　ComUtil.isArray(options.cfgCilckIgore) && 
						ComTable.isInArray(index, options.cfgCilckIgore)) {
					return;
				}
				var field = $(this).attr('data-field'), tr = $(this).parents('tr'), tid = tr.attr("data-tt-id"), 
					node = table.treetable('node',tid), record = node.row.data("data");
				options.cfgCellClick({
					field: field,
					record: record,
					node: node
				});
			});
		}*/
		
		// 方法2：行和单元格事件统一进行管理
		$(obj + ' tbody tr').off('click').on('click', 'td',  function (e) {
			// 添加选中样式
			ComTable.selectTr(this, options);
			
			var index = $(this).index();
			if (index === options.column) {
				return;
			}
			// TODO 取消点击事件的列用于用户自动以点击单元格内的按钮或链接事件
			if (options.cfgCilckIgore &&　ComUtil.isArray(options.cfgCilckIgore) && 
					ComTable.isInArray(index, options.cfgCilckIgore)) {
				return;
			}
			var result = (function _result(obj){
				var field = $(obj).attr('data-field'), tid = $(obj).parents('tr').attr("data-tt-id"), 
				node = table.treetable('node',tid), record = node.row.data("data");
				return {
					field: field,
					record: record,
					node: node
				};
			})(this);
			
			if (options.cfgCellClick && typeof options.cfgCellClick === "function") {
				options.cfgCellClick(result);
			} else {
				if (options.cfgRowClick && typeof options.cfgRowClick === "function") {
					options.cfgRowClick(result);
				}
			}
		});
    }
    
    /**
	 * @param id 
	 * 搜索input  id
	 * @param table 
	 * 表格id
	 * @param colIndex
	 * 表格匹配列,默认0
	 */
	that.serachTableTree = function (id, table, colIndex){
		var str = $(id).val(),selectedClazz = "selected", colIndex = colIndex || 0;
		$(id).val("");
		// 把之前选择的去掉
		$(table).find("tr").find("td." + selectedClazz).removeClass(selectedClazz);
		$(table).find("tr").each(function(){
			var trObj = $(this);
	        var tdObj = $(this).children();
	        var obj_value = tdObj.eq(colIndex).html();
	        if (obj_value.indexOf(str) != -1) {
	        	var id = $(trObj).attr("data-tt-id")
		        $(table).treetable("reveal", id);
	        	tdObj.addClass(selectedClazz);
	        	$("body,html").animate({  
	                scrollTop: tdObj.offset().top-50  
	            });
	        }
	    });
	}
	
	/**
	 * 获取JQuery.datatable.js的checkbox勾选行的数据
	 * @param DTableObj
	 * JQuery.datatable对象,不是原始的ID,是JQuery.datatable对象,该对象由var table = $(obj).DataTable()获取
	 */
	that.getSelectedRows = function(DTableObj){
		var data = DTableObj.rows('.selected').data(),len = data.length;
		if (len > 0) {
			return data.slice(0,len);
		}
		return [];
	}
}